home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2000 / MacHack 2000.toast / pc / The Hacks / MacHacksBug / Python 1.5.2c1 / Extensions / Imaging / PIL / JpegImagePlugin.py < prev    next >
Encoding:
Text File  |  2000-06-23  |  9.4 KB  |  329 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id: JpegImagePlugin.py,v 1.1.1.2 1999/01/13 09:40:10 sjoerd Exp $
  4. #
  5. # JPEG (JFIF) file handling
  6. #
  7. # See "Digital Compression and Coding of Continous-Tone Still Images,
  8. # Part 1, Requirements and Guidelines" (CCITT T.81 / ISO 10918-1)
  9. #
  10. # History:
  11. #    95-09-09 fl    Created
  12. #    95-09-13 fl    Added full parser
  13. #    96-03-25 fl    Added hack to use the IJG command line utilities
  14. #    96-05-05 fl    Workaround Photoshop 2.5 CMYK polarity bug
  15. # 0.1    96-05-28 fl    Added draft support, JFIF version
  16. # 0.2    96-12-30 fl    Added encoder options, added progression property
  17. # 0.3    97-08-27 fl    Save mode 1 images as BW
  18. # 0.4    98-07-12 fl    Added YCbCr to draft and save methods
  19. # 0.4.1    98-10-19 fl    Don't hang on files using 16-bit DQT's
  20. #
  21. # Copyright (c) Secret Labs AB 1997-98.
  22. # Copyright (c) Fredrik Lundh 1995-96.
  23. #
  24. # See the README file for information on usage and redistribution.
  25. #
  26.  
  27. __version__ = "0.4.1"
  28.  
  29. import array, string
  30. import Image, ImageFile
  31.  
  32.  
  33. def i16(c):
  34.     return ord(c[1]) + (ord(c[0])<<8)
  35.  
  36. def i32(c):
  37.     return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
  38.  
  39. #
  40. # Parser
  41.  
  42. def Skip(self, marker):
  43.     self.fp.read(i16(self.fp.read(2))-2)
  44.  
  45. def APP(self, marker):
  46.     #
  47.     # Application marker.  Store these in the APP dictionary.
  48.     # Also look for well-known application markers.
  49.  
  50.     s = self.fp.read(i16(self.fp.read(2))-2)
  51.     self.app["APP%d" % (marker&15)] = s
  52.  
  53.     if marker == 0xFFE0 and s[:4] == "JFIF":
  54.         self.info["jfif"] = i16(s[5:])
  55.     if marker == 0xFFEE and s[:5] == "Adobe":
  56.         self.info["adobe"] = i16(s[5:])
  57.     self.info["adobe_transform"] = ord(s[11])
  58.  
  59. def SOF(self, marker):
  60.     #
  61.     # Start of frame marker.  Defines the size and mode of the
  62.     # image.  JPEG is colour blind, so we use some simple
  63.     # heuristics to map the number of layers to an appropriate
  64.     # mode.  Note that this could be made a bit brighter, by
  65.     # looking for JFIF and Adobe APP markers.
  66.  
  67.     s = self.fp.read(i16(self.fp.read(2))-2)
  68.     self.size = i16(s[3:]), i16(s[1:])
  69.  
  70.     self.bits = ord(s[0])
  71.     if self.bits != 8:
  72.     raise SyntaxError, "cannot handle %d-bit layers" % self.bits
  73.  
  74.     self.layers = ord(s[5])
  75.     if self.layers == 1:
  76.     self.mode = "L"
  77.     elif self.layers == 3:
  78.     self.mode = "RGB"
  79.     elif self.layers == 4:
  80.     self.mode = "CMYK"
  81.     else:
  82.     raise SyntaxError, "cannot handle %d-layer images" % self.layers
  83.  
  84.     if marker in [0xFFC2, 0xFFC6, 0xFFCA, 0xFFCE]:
  85.     self.info["progression"] = 1
  86.  
  87.     for i in range(6, len(s), 3):
  88.     t = s[i:i+3]
  89.     # 4-tuples: id, vsamp, hsamp, qtable
  90.     self.layer.append(t[0], ord(t[1])/16, ord(t[1])&15, ord(t[2]))
  91.  
  92. def DQT(self, marker):
  93.     #
  94.     # Define quantization table.  Support baseline 8-bit tables
  95.     # only.  Note that there might be more than one table in
  96.     # each marker.
  97.  
  98.     # FIXME: The quantization tables can be used to estimate the
  99.     # compression quality.
  100.  
  101.     s = self.fp.read(i16(self.fp.read(2))-2)
  102.     while len(s):
  103.     if len(s) < 65:
  104.         raise SyntaxError, "bad quantization table marker"
  105.     v = ord(s[0])
  106.     if v/16 == 0:
  107.         self.quantization[v&15] = array.array("b", s[1:65])
  108.         s = s[65:]
  109.     else:
  110.         return # FIXME: add code to read 16-bit tables!
  111.         # raise SyntaxError, "bad quantization table element size"
  112.  
  113.  
  114. #
  115. # JPEG marker table
  116.  
  117. MARKER = {
  118.     0xFFC0: ("SOF0", "Baseline DCT", SOF),
  119.     0xFFC1: ("SOF1", "Extended Sequential DCT", SOF),
  120.     0xFFC2: ("SOF2", "Progressive DCT", SOF),
  121.     0xFFC3: ("SOF3", "Spatial lossless", SOF),
  122.     0xFFC4: ("DHT", "Define Huffman table", Skip),
  123.     0xFFC5: ("SOF5", "Differential sequential DCT", SOF),
  124.     0xFFC6: ("SOF6", "Differential progressive DCT", SOF),
  125.     0xFFC7: ("SOF7", "Differential spatial", SOF),
  126.     0xFFC8: ("JPG", "Extension", None),
  127.     0xFFC9: ("SOF9", "Extended sequential DCT (AC)", SOF),
  128.     0xFFCA: ("SOF10", "Progressive DCT (AC)", SOF),
  129.     0xFFCB: ("SOF11", "Spatial lossless DCT (AC)", SOF),
  130.     0xFFCC: ("DAC", "Define arithmetic coding conditioning", Skip),
  131.     0xFFCD: ("SOF13", "Differential sequential DCT (AC)", SOF),
  132.     0xFFCE: ("SOF14", "Differential progressive DCT (AC)", SOF),
  133.     0xFFCF: ("SOF15", "Differential spatial (AC)", SOF),
  134.     0xFFD0: ("RST0", "Restart 0", None),
  135.     0xFFD1: ("RST1", "Restart 1", None),
  136.     0xFFD2: ("RST2", "Restart 2", None),
  137.     0xFFD3: ("RST3", "Restart 3", None),
  138.     0xFFD4: ("RST4", "Restart 4", None),
  139.     0xFFD5: ("RST5", "Restart 5", None),
  140.     0xFFD6: ("RST6", "Restart 6", None),
  141.     0xFFD7: ("RST7", "Restart 7", None),
  142.     0xFFD8: ("SOI", "Start of image", None),
  143.     0xFFD9: ("EOI", "End of image", None),
  144.     0xFFDA: ("SOS", "Start of scan", Skip),
  145.     0xFFDB: ("DQT", "Define quantization table", DQT),
  146.     0xFFDC: ("DNL", "Define number of lines", Skip),
  147.     0xFFDD: ("DRI", "Define restart interval", Skip),
  148.     0xFFDE: ("DHP", "Define hierarchical progression", SOF),
  149.     0xFFDF: ("EXP", "Expand reference component", Skip),
  150.     0xFFE0: ("APP0", "Application segment 0", APP),
  151.     0xFFE1: ("APP1", "Application segment 1", APP),
  152.     0xFFE2: ("APP2", "Application segment 2", APP),
  153.     0xFFE3: ("APP3", "Application segment 3", APP),
  154.     0xFFE4: ("APP4", "Application segment 4", APP),
  155.     0xFFE5: ("APP5", "Application segment 5", APP),
  156.     0xFFE6: ("APP6", "Application segment 6", APP),
  157.     0xFFE7: ("APP7", "Application segment 7", APP),
  158.     0xFFE8: ("APP8", "Application segment 8", APP),
  159.     0xFFE9: ("APP9", "Application segment 9", APP),
  160.     0xFFEA: ("APP10", "Application segment 10", APP),
  161.     0xFFEB: ("APP11", "Application segment 11", APP),
  162.     0xFFEC: ("APP12", "Application segment 12", APP),
  163.     0xFFED: ("APP13", "Application segment 13", APP),
  164.     0xFFEE: ("APP14", "Application segment 14", APP),
  165.     0xFFEF: ("APP15", "Application segment 15", APP),
  166.     0xFFF0: ("JPG0", "Extension 0", None),
  167.     0xFFF1: ("JPG1", "Extension 1", None),
  168.     0xFFF2: ("JPG2", "Extension 2", None),
  169.     0xFFF3: ("JPG3", "Extension 3", None),
  170.     0xFFF4: ("JPG4", "Extension 4", None),
  171.     0xFFF5: ("JPG5", "Extension 5", None),
  172.     0xFFF6: ("JPG6", "Extension 6", None),
  173.     0xFFF7: ("JPG7", "Extension 7", None),
  174.     0xFFF8: ("JPG8", "Extension 8", None),
  175.     0xFFF9: ("JPG9", "Extension 9", None),
  176.     0xFFFA: ("JPG10", "Extension 10", None),
  177.     0xFFFB: ("JPG11", "Extension 11", None),
  178.     0xFFFC: ("JPG12", "Extension 12", None),
  179.     0xFFFD: ("JPG13", "Extension 13", None),
  180.     0xFFFE: ("COM", "Comment", Skip)
  181. }
  182.  
  183.  
  184. def _accept(prefix):
  185.     return prefix[0] == "\377"
  186.  
  187. class JpegImageFile(ImageFile.ImageFile):
  188.  
  189.     format = "JPEG"
  190.     format_description = "JPEG (ISO 10918)"
  191.  
  192.     def _open(self):
  193.  
  194.     s = self.fp.read(1)
  195.  
  196.     if ord(s[0]) != 255:
  197.         raise SyntaxError, "not an JPEG file"
  198.  
  199.     # Create attributes
  200.     self.bits = self.layers = 0
  201.  
  202.     # JPEG specifics (internal)
  203.     self.layer = []
  204.     self.huffman_dc = {}
  205.     self.huffman_ac = {}
  206.     self.quantization = {}
  207.     self.app = {}
  208.  
  209.     while 1:
  210.  
  211.         s = s + self.fp.read(1)
  212.  
  213.         i = i16(s)
  214.  
  215.         if MARKER.has_key(i):
  216.         name, description, handler = MARKER[i]
  217.         # print hex(i), name, description
  218.         if handler is not None:
  219.             handler(self, i)
  220.         if i == 0xFFDA: # start of scan
  221.             rawmode = self.mode
  222.             if self.mode == "CMYK" and self.info.has_key("adobe"):
  223.             rawmode = "CMYK;I" # Photoshop 2.5 is broken!
  224.             self.tile = [("jpeg", (0,0) + self.size, 0, (rawmode, ""))]
  225.             # self.__offset = self.fp.tell()
  226.             break
  227.         s = self.fp.read(1)
  228.         else:
  229.             raise SyntaxError, "no marker found"
  230.  
  231.     def draft(self, mode, size):
  232.  
  233.     if len(self.tile) != 1:
  234.         return
  235.  
  236.     d, e, o, a = self.tile[0]
  237.     scale = 0
  238.  
  239.     if a[0] == "RGB" and mode in ["L", "YCbCr"]:
  240.         self.mode = mode
  241.         a = mode, ""
  242.  
  243.     if size:
  244.         scale = max(self.size[0] / size[0], self.size[1] / size[1])
  245.         for s in [8, 4, 2, 1]:
  246.         if scale >= s:
  247.             break
  248.         e = e[0], e[1], (e[2]-e[0]+s-1)/s+e[0], (e[3]-e[1]+s-1)/s+e[1]
  249.         self.size = ((self.size[0]+s-1)/s, (self.size[1]+s-1)/s)
  250.         scale = s
  251.  
  252.     self.tile = [(d, e, o, a)]
  253.     self.decoderconfig = (scale, 1)
  254.  
  255.     return self
  256.  
  257.     def load_djpeg(self, modify=0):
  258.  
  259.     # ALTERNATIVE: handle JPEGs via the IJG command line utilities
  260.  
  261.     import tempfile, os
  262.     file = tempfile.mktemp()
  263.     os.system("djpeg %s >%s" % (self.filename, file))
  264.  
  265.     try:
  266.         self.im = Image.core.open_ppm(file)
  267.     finally:
  268.         try: os.unlink(file)
  269.         except: pass
  270.  
  271.     self.mode = self.im.mode
  272.     self.size = self.im.size
  273.  
  274.     self.tile = []
  275.  
  276.  
  277. def _fetch(dict, key, default = 0):
  278.     try:
  279.     return dict[key]
  280.     except KeyError:
  281.     return default
  282.  
  283. RAWMODE = {
  284.     "1": "L",
  285.     "L": "L",
  286.     "RGB": "RGB",
  287.     "RGBA": "RGB",
  288.     "RGBX": "RGB",
  289.     "CMYK": "CMYK",
  290.     "YCbCr": "YCbCr",
  291. }
  292.  
  293. def _save(im, fp, filename):
  294.  
  295.     try:
  296.         rawmode = RAWMODE[im.mode]
  297.     except KeyError:
  298.     raise IOError, "cannot write mode %s as JPEG" % im.mode
  299.  
  300.     # get keyword arguments
  301.     im.encoderconfig = (_fetch(im.encoderinfo, "quality", 0),
  302.             im.encoderinfo.has_key("progressive"),
  303.             _fetch(im.encoderinfo, "smooth", 0),
  304.             im.encoderinfo.has_key("optimize"),
  305.             _fetch(im.encoderinfo, "streamtype", 0))
  306.  
  307.     ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)])
  308.  
  309. def _save_cjpeg(im, fp, filename):
  310.     # ALTERNATIVE: handle JPEGs via the IJG command line utilities.
  311.     import os
  312.     file = im._dump()
  313.     os.system("cjpeg %s >%s" % (file, filename))
  314.     try: os.unlink(file)
  315.     except: pass
  316.  
  317. # -------------------------------------------------------------------q-
  318. # Registry stuff
  319.  
  320. Image.register_open("JPEG", JpegImageFile, _accept)
  321. Image.register_save("JPEG", _save)
  322.  
  323. Image.register_extension("JPEG", ".jfif")
  324. Image.register_extension("JPEG", ".jpe")
  325. Image.register_extension("JPEG", ".jpg")
  326. Image.register_extension("JPEG", ".jpeg")
  327.  
  328. Image.register_mime("JPEG", "image/jpeg")
  329.